home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvitops / aftopl.c < prev    next >
C/C++ Source or Header  |  1991-01-25  |  12KB  |  517 lines

  1. static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/aftopl.c,v 1.4 89/10/02 10:39:25 jjc Rel $";
  2.  
  3. #include "util.h"
  4.  
  5. #define MAXNAMES 500
  6. #define NOT_DEFINED 100000.0
  7. #ifndef PI
  8. #define PI 3.14159265358979324
  9. #endif
  10.  
  11. struct ligatures {
  12.     char *ch;
  13.     char *succ;
  14.     char *lig;
  15. };
  16.  
  17. char *program_name = "aftopl";
  18.  
  19. static int lineno = 0;
  20.  
  21. FILE *infp;
  22. FILE *outfp;
  23. #ifdef PROTO
  24. int lookup(const char *);
  25. char *getkeyvalue(char *, int);
  26. void scan_char_metric(char *);
  27. void compute_font_dimens(void);
  28. void do_kern_pairs(int);
  29. void do_char_metrics(int);
  30. void do_afms(void);
  31. void print_font_dimens(void);
  32. void do_encoding(char *);
  33. void print_char_metrics(void);
  34. void print_lig_kerns(void);
  35. void do_ligatures(struct ligatures *);
  36. #endif
  37.  
  38. #define bad_afm_file() message(FATAL_ERROR, "bad afm file, line %d", lineno)
  39.  
  40. struct lig_kern_list {
  41.     struct lig_kern_list *next;
  42.     int succ; 
  43.     int lig; /* -1 if its a kern */
  44.     double x;
  45. };
  46.  
  47.  
  48. struct {
  49.     struct lig_kern_list *p;
  50.     char *name;
  51.     int code;
  52.     double llx;
  53.     double lly;
  54.     double urx;
  55.     double ury;
  56.     double wx;
  57. } table[MAXNAMES];
  58.  
  59. struct  {
  60.     int is_fixed_pitch;
  61.     double italic_angle;
  62.     double x_height;
  63.     /* we use max(urx - wx + italic_correction_space, 0) 
  64.        as the italic correction for each character */
  65.     double italic_correction_space;
  66.     double normal_space;
  67.     double normal_stretch;
  68.     double normal_shrink;
  69.     double extra_space;
  70.     double quad;
  71.     double slant;
  72. } font = { 0, 0.0, NOT_DEFINED, NOT_DEFINED, NOT_DEFINED, NOT_DEFINED, 
  73. NOT_DEFINED, NOT_DEFINED, NOT_DEFINED, NOT_DEFINED};
  74.  
  75.  
  76.  
  77. int lookup(s)
  78. const char *s;
  79. {
  80.     int i;
  81.     for (i = 0; i < MAXNAMES; i++)
  82.         if (table[i].name == NULL)
  83.             break;
  84.         else if (strcmp(table[i].name, s) == 0)
  85.             return i;
  86.     if (i == MAXNAMES)
  87.         message(FATAL_ERROR, "too many names");
  88.     if ((table[i].name = malloc(strlen(s) + 1)) == NULL)
  89.         message(FATAL_ERROR, "out of memory");
  90.     strcpy(table[i].name, s);
  91.     table[i].code = -2;
  92.     table[i].llx = table[i].lly = 0.0;
  93.     table[i].urx = table[i].ury = 0.0;
  94.     table[i].wx = 0.0;
  95.     table[i].p = NULL;
  96.     return i;
  97. }
  98.  
  99.  
  100. char *getkeyvalue(s, c)
  101. char *s; 
  102. char c;
  103. {
  104.     while (*s != '\0') {
  105.         while (isspace(*s))
  106.             s++;
  107.         if (*s == c)
  108.             return s + 1;
  109.         while (*s != '\0')
  110.             if (*s++ == ';')
  111.                 break;
  112.     }
  113.     return NULL;
  114. }
  115.  
  116. void scan_char_metric(s)
  117. char *s;
  118. {
  119.     char name[128];
  120.     int code, n;
  121.     double llx, lly, urx, ury;
  122.     double wx, wy;
  123.     char *p;
  124.     while (isspace(*s))
  125.         s++;
  126.     if (*s == '\0') /* ignore blank line */
  127.         return;
  128.     p = getkeyvalue(s, 'N');
  129.     if (p == NULL)
  130.         bad_afm_file();
  131.     /* sscanf(p, " %[A-Za-z0-9]", name); */
  132.     /* Microsoft C scanf doesn't understand %[ */
  133.     sscanf(p, "%s", name);
  134.     if ((p = strchr(name, ';')) != NULL)
  135.         *p = '\0';
  136.     if ((p = getkeyvalue(s, 'C')) == NULL)
  137.         bad_afm_file();
  138.     if (sscanf(p, "%d", &code) != 1)
  139.         bad_afm_file();
  140.     p = getkeyvalue(s, 'B');
  141.     if (p == NULL)
  142.         bad_afm_file();
  143.     if (sscanf(p, "%lg %lg %lg %lg", &llx, &lly, &urx, &ury) != 4)
  144.         bad_afm_file();
  145.     p = getkeyvalue(s, 'W');
  146.     if (p == NULL)
  147.         bad_afm_file();
  148.     if (*p == 'X') {
  149.         if (sscanf(p+1, "%lg", &wx) != 1)
  150.             bad_afm_file();
  151.         wy = 0.0;
  152.     }
  153.     else if (sscanf(p, "%lg %lg", &wx, &wy) != 2)
  154.         bad_afm_file();
  155.     n = lookup(name);
  156.     table[n].code = code;
  157.     table[n].wx = wx;
  158.     table[n].llx = llx;
  159.     table[n].lly = lly;
  160.     table[n].urx = urx;
  161.     table[n].ury = ury;
  162.     while ((p = getkeyvalue(s, 'L')) != NULL) {
  163.         char successor[128];
  164.         char ligature[128];
  165.         struct lig_kern_list *ptr;
  166.         if (sscanf(p, " %s %s", successor, ligature) != 2)
  167.             bad_afm_file();
  168.         else if ((s = strchr(ligature, ';')) != NULL)
  169.                 *s = '\0';
  170.         if ((s = strchr(p, ';')) == NULL)
  171.             bad_afm_file();
  172.         s++;
  173.         if ((ptr = (struct lig_kern_list *)malloc(sizeof(struct lig_kern_list))) == NULL)
  174.             message(FATAL_ERROR, "out of memory");
  175.         ptr->succ = lookup(successor);
  176.         ptr->lig = lookup(ligature);
  177.         ptr->next = table[n].p;
  178.         table[n].p = ptr;
  179.     }
  180. }
  181.  
  182.  
  183. void compute_font_dimens()
  184. {
  185.     if (font.normal_space == NOT_DEFINED) {
  186.         int n = lookup("space");
  187.         if (table[n].code == -2)
  188.             message(FATAL_ERROR, "no char metric for space character");
  189.         else
  190.             font.normal_space = table[n].wx;
  191.     }
  192.     if (font.quad == NOT_DEFINED)
  193.         font.quad = (font.is_fixed_pitch?2.0:3.0)*font.normal_space;
  194.     if (font.italic_correction_space == NOT_DEFINED)
  195.         font.italic_correction_space = font.normal_space/12.0;
  196.     if (font.normal_shrink == NOT_DEFINED)
  197.         font.normal_shrink = font.is_fixed_pitch ? 0.0 :
  198.                         font.normal_space/3.0;
  199.     if (font.normal_stretch == NOT_DEFINED)
  200.         font.normal_stretch = font.is_fixed_pitch ? 0.0 :
  201.                         font.normal_space/2.0;
  202.     if (font.extra_space == NOT_DEFINED)
  203.         font.extra_space = (font.is_fixed_pitch ? 1.0 :0.5)
  204.                     *font.normal_space;
  205.     if (font.slant == NOT_DEFINED)
  206.         if (font.italic_angle == 0.0)
  207.             font.slant = 0.0;
  208.         else
  209.             font.slant = sin(-font.italic_angle*PI/180.0);
  210.     if (font.x_height == NOT_DEFINED)
  211.         font.x_height = table[lookup("x")].ury;
  212. }
  213.  
  214. void do_kern_pairs(n)
  215. int n;
  216. {
  217.     char buf[512];
  218.     char name1[128];
  219.     char name2[128];
  220.     double x, y;
  221.     for (;;) {
  222.         int i;
  223.         struct lig_kern_list *ptr;
  224.         lineno++;
  225.         if (fgets(buf, 512, infp) == NULL)
  226.             bad_afm_file();
  227.         if (buf[0] == '\n')
  228.             continue;
  229.         if (strcmp(buf, "EndKernPairs\n") == 0)
  230.             break;
  231.         if (sscanf(buf, "KPX %s %s %lg", name1, name2, &x) != 3) {
  232.             if (sscanf(buf, "KP %s %s %lg %lg", name1, name2,
  233.                     &x, &y) != 4)
  234.                 bad_afm_file();
  235.         }
  236.         else
  237.             y = 0.0;
  238.         i = lookup(name1);
  239.         if ((ptr = (struct lig_kern_list *)malloc(sizeof(struct lig_kern_list))) == NULL)
  240.             message(FATAL_ERROR, "out of memory");
  241.         ptr->succ = lookup(name2);
  242.         ptr->lig = -1;
  243.         ptr->x = x;
  244.         ptr->next = table[i].p;
  245.         table[i].p = ptr;
  246.         n--;
  247.     }
  248.     if (n != 0)
  249.         message(WARNING, "wrong number of kern pairs");
  250. }
  251.  
  252.  
  253. void do_char_metrics(n)
  254. int n;
  255. {
  256.     char buf[512];
  257.     for (;;) {
  258.         char *ptr = buf;
  259.         lineno++;
  260.         if (fgets(buf, 512, infp) == NULL)
  261.             bad_afm_file();
  262.         if (strcmp(buf, "EndCharMetrics\n") == 0)
  263.             break;
  264.         while (isspace(*ptr))
  265.             ptr++;
  266.         if (*ptr == '\0')
  267.             continue;
  268.         scan_char_metric(buf);
  269.         n--;
  270.     }
  271.     if (n != 0) 
  272.         message(WARNING, "wrong number of char metrics");
  273. }
  274.  
  275. void do_afms()
  276. {
  277.     char buf[512];
  278.     lineno = 0;
  279.  
  280.     while (fgets(buf, 512, infp) != NULL) {
  281.         char *key, *value;
  282.         key = buf;
  283.         lineno++;
  284.         while (isspace(*key))
  285.             key++;
  286.         value = key;
  287.         while (*value != '\0' && !isspace(*value))
  288.             value++;
  289.         if (*value != '\0') {
  290.             /* strip trailing white space */
  291.             char *p;
  292.             *value++ = '\0';
  293.             while (isspace(*value))
  294.                 value++;
  295.             p = value;
  296.             while (*p != '\0')
  297.                 p++;
  298.             while (p > value && isspace(*(p-1)))
  299.                 p--;
  300.             *p = '\0';
  301.         }
  302.         if (strcmp(key, "IsFixedPitch") == 0)
  303.             font.is_fixed_pitch = (strcmp(value, "true") == 0);
  304.         else if (strcmp(key, "XHeight") == 0)
  305.             font.x_height = atof(value);
  306.         else if (strcmp(key, "StartCharMetrics") == 0)
  307.             do_char_metrics(atoi(value));
  308.         else if (strcmp(key, "ItalicAngle") == 0)
  309.             font.italic_angle = atof(value);
  310.         else if (strcmp(key, "StartKernPairs") == 0)
  311.             do_kern_pairs(atoi(value));
  312.         else if (strcmp(key, "italicCorrectionSpace") == 0)
  313.             font.italic_correction_space = atof(value);
  314.     }
  315.  
  316. }
  317.  
  318.  
  319. void print_font_dimens()
  320. {
  321.     fprintf(outfp, "(FONTDIMEN\n");
  322.     fprintf(outfp, "    (SLANT R %f)\n", font.slant);
  323.     fprintf(outfp, "    (SPACE R %f)\n", font.normal_space/1000.0);
  324.     fprintf(outfp, "    (SHRINK R %f)\n", font.normal_shrink/1000.0);
  325.     fprintf(outfp, "    (STRETCH R %f)\n", font.normal_stretch/1000.0);
  326.     fprintf(outfp, "    (EXTRASPACE R %f)\n", font.extra_space/1000.0);
  327.     fprintf(outfp, "    (QUAD R %f)\n", font.quad/1000.0);
  328.     fprintf(outfp, "    (XHEIGHT R %f)\n", font.x_height/1000.0);
  329.     fprintf(outfp, "    )\n");
  330. }
  331.  
  332.  
  333. void do_encoding(encoding)
  334. char *encoding;
  335. {
  336.     int i;
  337.     char name[256];
  338.     FILE *fp;
  339.     char *texfonts;
  340.     fprintf(outfp, "(CODINGSCHEME %s)\n", encoding);
  341.     texfonts = getenv("TEXFONTS");
  342.     if (texfonts == NULL)
  343.         texfonts = TEXFONTS;
  344.     if ((fp = xfopen(encoding, FALSE, texfonts, ".enc")) == NULL)
  345.         message(FATAL_ERROR, "can't find %s", encoding);
  346.     for (i = 0; i < MAXNAMES; i++)
  347.         if (table[i].code >= -1)
  348.             table[i].code = -1;
  349.     for (i = 0; i < 256 && fscanf(fp, " %s ", name) == 1;  i++) {
  350.         int n;
  351.         if (strcmp(".notdef", name) == 0)
  352.             continue;
  353.         n = lookup(name);
  354.         if (table[n].code == -2)
  355.             message(WARNING, "%s in encoding but not in font", name);
  356.         else if (table[n].code == -1)
  357.             table[n].code = i;
  358.         else
  359.             message(ERROR, "%s appears more than once in encoding", name);
  360.     }
  361. }
  362.  
  363.  
  364.  
  365. void print_char_metrics()
  366. {
  367.     int i;
  368.     for (i = 0; i < MAXNAMES; i++)
  369.         if (table[i].name != NULL && table[i].code > 0) {
  370.             double charic;
  371.             fprintf(outfp, "(CHARACTER O %03o\n", table[i].code);
  372.             fprintf(outfp, "    (COMMENT %s)\n", table[i].name);
  373.             fprintf(outfp, "    (CHARWD R %f)\n", 
  374.                             table[i].wx/1000.0);
  375.             /* negative heights and depths mess up \mathaccent */
  376.             if (table[i].ury > 0.0)
  377.                 fprintf(outfp, "    (CHARHT R %f)\n", 
  378.                             table[i].ury/1000.0);
  379.             if (table[i].lly < 0.0)
  380.                 fprintf(outfp, "    (CHARDP R %f)\n",
  381.                             -table[i].lly/1000.0);
  382.             charic = table[i].urx - table[i].wx + font.italic_correction_space;
  383.             if (charic > 0.0)
  384.                 fprintf(outfp, "    (CHARIC R %f)\n", 
  385.                     charic/1000.0);
  386.             fputs("    )\n", outfp);
  387.         }
  388. }
  389.  
  390.  
  391.  
  392. void print_lig_kerns()
  393. {
  394.     int i;
  395.     fputs("(LIGTABLE\n", outfp);
  396.     for (i = 0; i < MAXNAMES; i++) {
  397.         struct lig_kern_list *p;
  398.         char label_line[128];
  399.         if (table[i].name == NULL || table[i].code < 0)
  400.             continue;
  401.         sprintf(label_line, "    (LABEL O %03o)\n", table[i].code);
  402.         /* print the ligatures */
  403.         for (p = table[i].p; p != NULL; p = p->next)
  404.             if (p->lig != -1 && table[p->lig].code > 0
  405.                     && table[p->succ].code > 0) {
  406.                 fputs(label_line, outfp);
  407.                 label_line[0]= '\0';
  408.                 fprintf(outfp,"    (LIG O %03o O %03o)\n",
  409.                     table[p->succ].code,
  410.                     table[p->lig].code);
  411.             }
  412.         for (p = table[i].p; p != NULL; p = p->next)
  413.             if (p->lig == -1 && table[p->succ].code > 0) {
  414.                 fputs(label_line, outfp);
  415.                 label_line[0] = '\0';
  416.                 fprintf(outfp, "    (KRN O %03o R %f)\n",
  417.                     table[p->succ].code,
  418.                     p->x/1000.0);
  419.             }
  420.         if (label_line[0] == '\0')
  421.             fputs("    (STOP)\n", outfp);
  422.     }
  423.     fputs("    )\n", outfp);
  424. }
  425.  
  426.  
  427. struct ligatures standard_ligatures[] = {
  428.     "hyphen", "hyphen", "endash",
  429.     "endash", "hyphen", "emdash",
  430.     "quoteleft", "quoteleft", "quotedblleft",
  431.     "quoteright", "quoteright", "quotedblright",
  432.     "exclam", "quoteleft", "exclamdown",
  433.     "question", "quoteleft", "questiondown",
  434.     NULL, NULL, NULL 
  435.     };
  436.  
  437. struct ligatures tt_ligatures[] = {
  438.     "exclam", "quoteleft", "exclamdown",
  439.     "question", "quoteleft", "questiondown",
  440.     NULL, NULL, NULL
  441.     };
  442.  
  443.  
  444. void do_ligatures(lig)
  445. struct ligatures *lig;
  446. {
  447.     int i;
  448.     for (i = 0; lig[i].lig != NULL; i++) {
  449.         int n;
  450.         struct lig_kern_list *p;
  451.         n = lookup(lig[i].ch);
  452.         if ((p = (struct lig_kern_list *)malloc(sizeof(struct lig_kern_list))) == NULL)
  453.             message(FATAL_ERROR, "out_of_memory");
  454.         p->succ = lookup(lig[i].succ);
  455.         p->lig = lookup(lig[i].lig);
  456.         p->next = table[n].p;
  457.         table[n].p = p;
  458.     }
  459. }
  460.  
  461.  
  462.  
  463. int main(argc, argv)
  464. int argc;
  465. char **argv;
  466. {
  467.     char filename[128];
  468.     int c;
  469.     char *efile = NULL;
  470.     int nolig = FALSE;
  471.     while ((c = getopt(argc, argv, "ne:")) != EOF)
  472.         switch(c) {
  473.         case 'n':
  474.                 nolig = TRUE;
  475.             break;
  476.         case 'e':
  477.             efile = optarg;
  478.             break;
  479.         case '?':
  480.             goto usage;
  481.         }
  482.     if (argc - optind < 1)
  483.         goto usage;
  484.     strcpy(filename, argv[optind]);
  485.     if (strchr(filename, '.') == NULL)
  486.         strcat(filename, ".afm");
  487.     if ((infp = fopen(filename, "r")) == NULL)
  488.         message(FATAL_ERROR, "can't open %s", filename);
  489.     if (argc - optind == 1)
  490.         strcpy(strchr(filename, '.'), ".pl");
  491.     else if (argc - optind == 2) {
  492.         strcpy(filename, argv[optind+1]);
  493.         if (strchr(filename, '.') == NULL)
  494.             strcat(filename, ".pl");
  495.     }
  496.     else
  497.         goto usage;
  498.     if ((outfp = fopen(filename, "w")) == NULL)
  499.         message(FATAL_ERROR, "can't open %s", filename);
  500.     do_afms();
  501.     if (efile != NULL)
  502.         do_encoding(efile);
  503.     if (!nolig) {
  504.             if (font.is_fixed_pitch)
  505.               do_ligatures(tt_ligatures);
  506.         else
  507.               do_ligatures(standard_ligatures);
  508.     }
  509.     compute_font_dimens();
  510.     print_font_dimens();
  511.     print_char_metrics();
  512.     print_lig_kerns();
  513.     exit(history);
  514. usage:
  515.     message(FATAL_ERROR, "usage: aftopl [-e encoding] afmfile [plfile]");
  516. }
  517.